package com.gitee.sparta.core.process.feature;

import com.gitee.sparta.common.SpartaConstant;
import com.gitee.sparta.common.helpers.JacksonHelper;
import com.gitee.sparta.common.helpers.RedisKeyHelper;
import com.gitee.sparta.core.bean.SpartaChannel;
import com.gitee.sparta.core.bean.metadata.Metadata;
import com.gitee.sparta.core.process.operate.ReadableTabOperate;
import com.gitee.sparta.core.property.SpartaCoreProperties;
import lombok.extern.slf4j.Slf4j;


/**
 * 分布式续签特性
 *
 * @author zyred
 * @since v 0.0.1
 */
@Slf4j
public class SpartaDistributedRenewFeature<V> {

    private final SpartaCoreProperties properties;
    private final ReadableTabOperate<V> readableTabOperate;

    public SpartaDistributedRenewFeature(SpartaCoreProperties properties,
                                         ReadableTabOperate<V> readableTabOperate) {
        this.properties = properties;
        this.readableTabOperate = readableTabOperate;
    }


    /**
     * 开始执行重试， 此重试是分布式的重试，防止单机失败的情况出现
     *
     * @param fullTopic         完整的 topic：topic:metaId
     * @param listenTopic       @SpartaListener 内中 topics 描述
     * @param metadata          被深拷贝的 body 对象，防止用户在回调方法中进行修改内容
     * @param channel           用户 ack 等操作的运用
     */
    public void doProcessRenew(final String fullTopic, final String listenTopic, Metadata<V> metadata, SpartaChannel channel) {

        // 分段消费时候，不支持续期
        if (metadata.isSegment()) {
            log.warn("[Sparta] Renew segment not support renew, topic: {}, body: {}",
                    listenTopic, JacksonHelper.serialize(metadata.getBody()));
            // 直接删除分段 TODO sparta_plan -> 9
            this.doDelMetadataReadableTab(listenTopic, fullTopic);
            return;
        }

        // 超过续期次数限制 - 1
        if (metadata.getRenewNumber() >= (properties.getRenew() - 1)) {
            if (log.isWarnEnabled()) {
                log.warn("[Sparta] Renewed more than {} times, no longer renew.", properties.getRenew());
            }
            this.doDelMetadataReadableTab(listenTopic, fullTopic);
            return;
        }

        this.doRenew(metadata, channel, listenTopic, fullTopic);
    }

    /**
     * 执行删除操作 删除 metadata_tab 与 readable_tab
     *
     * @param listenTopic   @SpartaListener 中 topics 的标注
     * @param fullTopic     完整的 topic:  topic:metaId
     */
    private void doDelMetadataReadableTab (final String listenTopic, final String fullTopic) {
        // 删除消息 metadata timeout ready
        final String readableTabKey = RedisKeyHelper.readableKey(this.properties.getSystemName(),
                this.properties.getIsolation(), listenTopic);
        final String metadataTabKey = RedisKeyHelper.tabKey(this.properties.getSystemName(),
                SpartaConstant.TABLE_METADATA_NAME);
        this.readableTabOperate.delMetadataReadableTab(fullTopic, readableTabKey, metadataTabKey);
    }

    private void doRenew(Metadata<V> metadata, SpartaChannel channel, final String listenTopic, final String fullTopic) {

        final String readableTabKey = RedisKeyHelper.readableKey(this.properties.getSystemName(),
                this.properties.getIsolation(), listenTopic);
        final String metadataTabKey = RedisKeyHelper.tabKey(this.properties.getSystemName(),
                SpartaConstant.TABLE_METADATA_NAME);
        final String timeoutTabKey = RedisKeyHelper.tabKey(this.properties.getSystemName(),
                SpartaConstant.TABLE_TIMEOUT_NAME);

        metadata.setRenewNumber(metadata.getRenewNumber() + 1);
        metadata.setExpire(System.currentTimeMillis() + channel.getRenewIntervalTime());
        this.readableTabOperate.renewOrRetry(readableTabKey, timeoutTabKey, metadataTabKey, fullTopic, metadata);
        log.info("[Sparta] Renew topic: {} renew number: {}", listenTopic, metadata.getRenewNumber());
    }
}
